import * as THREE from 'three'
import { STLLoader } from 'three/examples/jsm/loaders/STLLoader.js'

/**
 * STL模型加载器
 * 专门用于加载和缓存STL格式的3D打印模型
 */
class STLModelLoader {
  constructor() {
    this.cache = new Map()
    this.loader = new STLLoader()
    this.loadingPromises = new Map()
    this.stats = {
      totalLoaded: 0,
      totalCached: 0,
      cacheHits: 0,
      cacheMisses: 0
    }
  }

  /**
   * 加载STL模型
   * @param {string} path STL文件路径
   * @param {Object} options 加载选项
   * @returns {Promise<THREE.Mesh>} 加载的STL模型
   */
  async loadSTL(path, options = {}) {
    const {
      color = 0x4facfe,
      metalness = 0.3,
      roughness = 0.4,
      enableCaching = true,
      onProgress = null
    } = options

    // 检查缓存
    if (enableCaching && this.cache.has(path)) {
      this.stats.cacheHits++
      console.log(`从缓存加载STL模型: ${path}`)
      const cachedModel = this.cache.get(path)
      return this._cloneSTLModel(cachedModel)
    }

    // 检查是否正在加载
    if (this.loadingPromises.has(path)) {
      console.log(`等待STL模型加载完成: ${path}`)
      return await this.loadingPromises.get(path)
    }

    // 开始加载
    this.stats.cacheMisses++
    const loadingPromise = this._loadSTLFromFile(path, options)
    this.loadingPromises.set(path, loadingPromise)

    try {
      const model = await loadingPromise
      
      // 缓存模型
      if (enableCaching) {
        this.cache.set(path, model)
        this.stats.totalCached++
      }

      this.stats.totalLoaded++
      this.loadingPromises.delete(path)
      
      return this._cloneSTLModel(model)

    } catch (error) {
      this.loadingPromises.delete(path)
      throw error
    }
  }

  /**
   * 从文件加载STL模型
   * @private
   */
  async _loadSTLFromFile(path, options) {
    const { color, metalness, roughness, onProgress } = options

    return new Promise((resolve, reject) => {
      this.loader.load(
        path,
        (geometry) => {
          console.log(`STL模型加载成功: ${path}`)
          
          // 计算法向量和边界
          geometry.computeVertexNormals()
          geometry.computeBoundingSphere()
          geometry.computeBoundingBox()
          
          // 居中模型
          geometry.center()
          
          // 创建材质
          const material = new THREE.MeshStandardMaterial({
            color: color,
            metalness: metalness,
            roughness: roughness,
            flatShading: false,
            side: THREE.DoubleSide
          })
          
          // 创建网格
          const mesh = new THREE.Mesh(geometry, material)
          mesh.castShadow = true
          mesh.receiveShadow = true
          
          // 调整坐标系：交换y轴和z轴（STL通常z轴向上，Three.js y轴向上）
          mesh.rotation.x = -Math.PI / 2 // 绕x轴旋转-90度，将z轴变为y轴
          
          // 自动缩放到合适大小
          const boundingBox = geometry.boundingBox
          const size = boundingBox.getSize(new THREE.Vector3())
          const maxDimension = Math.max(size.x, size.y, size.z)
          
          // 将模型缩放到大约20个单位
          const targetSize = 20
          const scale = targetSize / maxDimension
          mesh.scale.setScalar(scale)
          
          // 添加一些元数据
          mesh.userData = {
            originalPath: path,
            originalSize: size,
            scaleFactor: scale,
            loadTime: Date.now()
          }

          resolve(mesh)
        },
        (progress) => {
          if (onProgress) {
            const percentage = progress.total > 0 
              ? (progress.loaded / progress.total) * 100 
              : 0
            onProgress(percentage, progress)
          }
        },
        (error) => {
          console.error(`STL模型加载失败: ${path}`, error)
          reject(error)
        }
      )
    })
  }

  /**
   * 克隆STL模型
   * @private
   */
  _cloneSTLModel(originalMesh) {
    const clonedGeometry = originalMesh.geometry.clone()
    const clonedMaterial = originalMesh.material.clone()
    const clonedMesh = new THREE.Mesh(clonedGeometry, clonedMaterial)
    
    // 复制变换和用户数据
    clonedMesh.position.copy(originalMesh.position)
    clonedMesh.rotation.copy(originalMesh.rotation)
    clonedMesh.scale.copy(originalMesh.scale)
    clonedMesh.userData = { ...originalMesh.userData }
    
    // 确保坐标系调整被复制
    if (!clonedMesh.rotation.x) {
      clonedMesh.rotation.x = -Math.PI / 2
    }
    
    clonedMesh.castShadow = true
    clonedMesh.receiveShadow = true
    
    return clonedMesh
  }

  /**
   * 预加载STL模型
   * @param {string} path STL文件路径
   * @param {Object} options 加载选项
   * @returns {Promise<boolean>} 预加载是否成功
   */
  async preloadSTL(path, options = {}) {
    try {
      await this.loadSTL(path, options)
      console.log(`STL模型预加载成功: ${path}`)
      return true
    } catch (error) {
      console.error(`STL模型预加载失败: ${path}`, error)
      return false
    }
  }

  /**
   * 批量预加载STL模型
   * @param {Array} paths STL文件路径数组
   * @param {Object} options 加载选项
   * @returns {Promise<Array>} 预加载结果数组
   */
  async preloadMultipleSTL(paths, options = {}) {
    const results = await Promise.allSettled(
      paths.map(path => this.preloadSTL(path, options))
    )
    
    const successful = results.filter(r => r.status === 'fulfilled' && r.value).length
    console.log(`批量预加载STL模型完成: ${successful}/${paths.length}`)
    
    return results
  }

  /**
   * 获取缓存信息
   * @returns {Object} 缓存统计信息
   */
  getCacheInfo() {
    return {
      cachedModels: this.cache.size,
      loadingModels: this.loadingPromises.size,
      stats: { ...this.stats },
      memoryUsage: this._calculateMemoryUsage()
    }
  }

  /**
   * 计算内存使用量（估算）
   * @private
   */
  _calculateMemoryUsage() {
    let totalVertices = 0
    let totalFaces = 0

    this.cache.forEach((mesh) => {
      if (mesh.geometry) {
        const positionAttribute = mesh.geometry.attributes.position
        if (positionAttribute) {
          totalVertices += positionAttribute.count
          totalFaces += positionAttribute.count / 3
        }
      }
    })

    return {
      estimatedVertices: totalVertices,
      estimatedFaces: Math.round(totalFaces),
      estimatedMemoryMB: Math.round((totalVertices * 12) / 1024 / 1024 * 100) / 100
    }
  }

  /**
   * 清理缓存
   * @param {string} path 可选，指定要清理的模型路径
   */
  clearCache(path = null) {
    if (path) {
      if (this.cache.has(path)) {
        const mesh = this.cache.get(path)
        this._disposeMesh(mesh)
        this.cache.delete(path)
        console.log(`清理STL模型缓存: ${path}`)
      }
    } else {
      // 清理所有缓存
      this.cache.forEach((mesh, path) => {
        this._disposeMesh(mesh)
      })
      this.cache.clear()
      console.log('清理所有STL模型缓存')
    }
  }

  /**
   * 释放网格资源
   * @private
   */
  _disposeMesh(mesh) {
    if (mesh.geometry) {
      mesh.geometry.dispose()
    }
    if (mesh.material) {
      if (mesh.material.map) mesh.material.map.dispose()
      if (mesh.material.normalMap) mesh.material.normalMap.dispose()
      mesh.material.dispose()
    }
  }

  /**
   * 销毁加载器
   */
  destroy() {
    this.clearCache()
    this.loadingPromises.clear()
    this.stats = {
      totalLoaded: 0,
      totalCached: 0,
      cacheHits: 0,
      cacheMisses: 0
    }
  }
}

// 创建单例实例
const stlLoader = new STLModelLoader()

export default stlLoader
